/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package intopo.evogame.partnerselection.config;

import cern.jet.random.engine.MersenneTwister;
import intopo.evogame.partnerselection.Cache;
import intopo.evogame.partnerselection.EvolutionaryAlgorithm;
import intopo.evogame.partnerselection.chromosome.Chromosome;
import intopo.evogame.partnerselection.chromosome.ChromosomeFactory;
import intopo.evogame.partnerselection.player.PlainPlayer;
import intopo.evogame.partnerselection.player.PlayerFactory;
import intopo.evogame.partnerselection.population.GeographicPopulation;
import intopo.game.DescriptionText;
import intopo.game.Game;
import intopo.game.Strategy;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Scanner;


/**
 * A text configuration file that contains data to perform a simulation of
 * the evolution of partner selection with plain players.
 *
 * <p> After reading a text file, the fields of this class contain the game
 * and the population that are going to be used by the evolutionary
 * algorithm.  Also global parameters that affect the behaviour of
 * chromosomes and plain players have new values, read from the file.
 *
 * <p> The format of the text file is composed of three main sections.  The
 * first section contains the global parameters values.  The second section
 * contains the game parameters.  The third and last section contain the
 * population data.
 *
 * @author <a href="mailto:mariano.pedro@gmail.com">Pedro Mariano</a>
 *
 * @version 1.0
 *
 * @see intopo.evogame.partnerselection.player.PlainPlayer
 *
 * @param <G> Type parameter that represents the game that is going to be
 * used in the evoluationary algorithm.
 *
 * @param <S> Type parameter that represents the game strategy that is
 * going to be used by players in the evolutionary algorithm.
 */
final public class TextConfigFilePlainPlayersEvoGame<
		G extends Game<S>,
		S extends Strategy<S>>
	extends AbstractTextConfigFilePlainPlayers<DescriptionText<G, S>, G, S>
{
	/**
	 * The population that is going to be used by the evolutionary algorithm.
	 */
	private GeographicPopulation<S, Chromosome<S>, PlainPlayer<S>> population;
	/**
	 * Construct a text configuration file that uses the given game
	 * description to read game and strategy data.
	 *
	 * @param description
	 */
	public TextConfigFilePlainPlayersEvoGame (DescriptionText<G, S> description)
	{
		super (description);
		this.population = null;
	}
	/**
	 * Read a text configuration file and return an instance of an
	 * evolutionary algorithm.  If an error occurs, a message is printed in
	 * the standard error output stream and {@code null} is returned.  This
	 * method treats the exceptions raised by method {@code read(String)}.
	 *
	 * @param configFilename The name of the text configuration file.
	 *
	 * @return An instance of an evolutionary algorithm constructed from the
	 * data in the configuration file.
	 *
	 * @see #read(java.lang.String)
	 */
	public intopo.evogame.partnerselection.EvolutionaryAlgorithm<G, S, Chromosome<S>, PlainPlayer<S>> readEvoGame (String configFilename)
	{
		try {
			this.read (configFilename);
			return new EvolutionaryAlgorithm<G, S, Chromosome<S>, PlainPlayer<S>> (this.game, this.population);
		}
		catch (ParsingException ex) {
			System.err.println ("Error parsing configuration file + '" + configFilename + "'");
			System.err.println ("Reading '" + ex.getLocalizedMessage () + "'");
			if (ex.getContents () == null) {
				System.err.println ("No line available");
			}
			else {
				System.err.println ("at line '" + ex.getContents () + "'");
			}
			return null;
		}
		catch (FileNotFoundException ex) {
			System.err.println ("Configuration file '" + configFilename
					  + "' not found\n" + ex.getLocalizedMessage ());
			return null;
		}
		catch (TagException ex) {
			System.err.println ("Error reading configuration file.  Tag '"
				+ ex.getTag ()
				+ "' does not correspond to any constructor in game '"
				+ this.description.getClass ().getName ());
			return null;
		}
		catch (ConstructGameException ex) {
			System.err.println ("Error creating the instance of game '"
				+ this.description.getClass ().getName ()
				+ "\nCause was:\n"
				+ ex.getCause ().getLocalizedMessage ());
			return null;
		}
		catch (ConstructStrategyException ex) {
			System.err.println ("Error creating an instance of a strategy of game '"
				+ this.description.getClass ().getName ()
				+ "\nCause was:\n"
				+ ex.getCause ().getLocalizedMessage ());
			return null;
		}
		catch (IOException ex) {
			System.err.println ("Error writing data to the database.\nDetailed info:\n");
			ex.printStackTrace (System.err);
			return null;
		}
	}

	/**
	 * Get the population that was read from the text file.
	 *
	 * <p> If method {@code read(String)} has not been called, the exception
	 * {@code IllegalStateException} is thrown.  This method always returns
	 * the population that was constructed from the last read.
	 *
	 * @see #read(java.lang.String)
	 *
	 * @return the population that was read from the text file.
	 *
	 * @throws java.lang.IllegalStateException If method {@code
	 * read(String)} has not been called.
	 */
	public GeographicPopulation<S, Chromosome<S>, PlainPlayer<S>> getPopulation ()
		throws IllegalStateException
	{
		if (this.population == null) {
			throw new IllegalStateException ("Configuration file has not been read");
		}
		else {
			return this.population;
		}
	}


	@Override
	protected void readPopulation (Scanner scanner)
		throws
			ConstructStrategyException,
			TagException,
			ParsingException,
			IOException
	{
		Cache.init (this.game, new MersenneTwister (new java.util.Date ()));
		PlayerFactory<S, Chromosome<S>, PlainPlayer<S>> playerFactory = PlainPlayer.<S>getFactory ();
		ChromosomeFactory<S, Chromosome<S>> chromosomeFactory = Chromosome.<S>getFactory ();
		this.population = new GeographicPopulation<S, Chromosome<S>, PlainPlayer<S>> (
			scanner,
			playerFactory, chromosomeFactory, description.getStrategyConstructors ());
	}

	@Override
	protected void writePopulation (PrintStream ps)
	{
		throw new UnsupportedOperationException ("Write population is not supported in TextConfigFilePlainPlayersEvoGame.");
	}
}

// Local Variables:
// mode: java
// mode: flyspell-prog
// ispell-local-dictionary: "british"
// End:
